package Thread_;

import java.util.PriorityQueue;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 模拟实现计时器
 */
//执行定时器要完成的功能
    //通过这个类,来完成要执行的任务
class MyTimerTask implements Comparable<MyTimerTask>{//实现Comparable接口,
                                        //重写compareTo方法,按照执行时间从小到大入队列
    //要完成任务的时间点(绝对时间)
    private long time;
    //实际要完成任务执行的代码
    public Runnable runnable;

    public long getTime(){
        return time;
    }
    //dalay是一个相对时间,
    public MyTimerTask(Runnable runnable,long delay){
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;
    }
    public void run(){
        runnable.run();
    }
    @Override
    public int compareTo(MyTimerTask o) {
        return (int)(this.time-o.time);
    }
}

class MyTimer{
    //负责扫描queue任务队列,执行任务的线程
//    public Thread t=null;
    Object locker=new Object();
    //任务队列
    PriorityQueue<MyTimerTask> queue = new PriorityQueue<>();
    //构造方法
    public MyTimer(){
        //创建扫描线程,让该线程频繁扫描队首元素,判断队首元素的时间是否到了
        //到了就执行任务,让后将该任务从队列中删除
        //没到就等一会
        new Thread(()->{
            try {
                while (true) {
                    //多线程下,有对队列的修改,会存在线程安全问题,需要加锁处理:主要是防止对队列的修改引发的线程安全
                    synchronized (locker) {
                        //队列为空,先停一下
                        if (queue.isEmpty()) {
//                        continue;
                            //当队列为空时,进行wait等待
                            locker.wait();
                        }
                        MyTimerTask top = queue.peek();
                        long curTime = System.currentTimeMillis();
                        if (curTime >= top.getTime()) {
                            //时间到了,执行代码,将队首元素删除
                            queue.poll();
                            top.run();
                        } else {
                            //时间没到,再等一下
//                            continue;
                            //t: 最近任务执行时间 离 当前时间,要等多长时间
                            long t=top.getTime()-curTime;
                            //要执行任务时间还没到时,就进行超时等待
                            locker.wait(t);
                        }
                    }
                }
            }catch(InterruptedException e){
                e.printStackTrace();
            }
        }).start();
//        t.start();
    }
    //传送 要执行的代码 将任务加入队列
    public void schedule(Runnable runnable,long delay){
        //这里也有对队列的修改,要加锁
        synchronized(locker){
            MyTimerTask myTimerTask = new MyTimerTask(runnable, delay);
            queue.offer(myTimerTask);
            //有任务进入队列,就可以唤醒扫描的wait
            locker.notify();
        }
    }
}


class MyTimerTask1 implements Comparable<MyTimerTask1>{
                                ///实现Comparable接口,
                                //重写compareTo方法,按照执行时间从小到大入队列
    private long time;//指定要执行任务的标准时间
    private Runnable runnable;//要执行的任务
    public MyTimerTask1(Runnable runnable,long delay){
                     //runnable:要执行的任务   delay是一个相对时间:要执行的任务距当前的时间,单位ms
        this.runnable=runnable;
        this.time=System.currentTimeMillis()+delay;//获取绝对时间
    }
    //获取执行时间
    public long getTime(){
        return time;
    }
    public void run(){
        runnable.run();
    }

    @Override
    public int compareTo(MyTimerTask1 o) {
        return (int)(this.time-o.time);
    }
}
class MyTimer1{
    //创建优先级队列
    private PriorityQueue<MyTimerTask1> queue=new PriorityQueue();
    //构造器 一旦实例化了该类对象,就让其一直扫描队列,通过创建线程来完成
    Object locker=new Object();
    public MyTimer1(){
        //创建扫描线程,并启动
        new Thread(()->{
            //循环扫描
            try{
                while(true){
                    //在这个过程中可能会因修改队列带来线程安全问题,要加锁
                    synchronized(locker){
                    //先判断队列是否为空
                        while(queue.isEmpty()){
                            //为空,就先等待一会
    //                        continue;
                            //队列为空时,进入阻塞状态,并释放锁,让schedule方法获取到锁,进行新任务入队列
                            locker.wait();
                        }
                        MyTimerTask1 head=queue.peek();//获取队头元素
                        long curTime=System.currentTimeMillis();//获取当前时间
                        if(curTime>=head.getTime()){
                            //到达任务要执行时间,执行任务,并将任务从队列中删除
                            head.run();
                            queue.poll();
                        }else{
                            //任务执行时间没到,等一会
//                            continue;
                            long time=head.getTime()-curTime;
                            locker.wait(time);//这里进行超时阻塞,当到达了要执行时间就停止阻塞
                        }
                    }
                }
            }catch(InterruptedException e){
                e.fillInStackTrace();
            }
        }).start();
    }
    //创建要执行的任务对象,并将其入队列
    public void schedule(Runnable runnable,long delay ){
        //将任务入队列时,也涉及到队列的修改操作,也要加锁
        synchronized(locker){
            //创建任务对象
            MyTimerTask1 myTimerTask1 = new MyTimerTask1(runnable, delay);
            //入队列
            queue.offer(myTimerTask1);
            //入队列后,队列不空,唤醒wait阻塞
            locker.notify();
        }
    }
}
public class Thread21 {
    public static void main(String[] args) {
        MyTimer timer = new MyTimer();
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("计时器 3s");
                }
            },3000);
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("计时器 2s");
                }
            },2000);
            timer.schedule(new TimerTask() {
                @Override
                public void run() {
                    System.out.println("计时器 1s");
                }
            },1000);
        System.out.println("main");
    }

    public static void main1(String[] args) {
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("计时器 3s");
            }
        },3000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("计时器 2s");
            }
        },2000);
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                System.out.println("计时器 1s");
            }
        },1000);
        System.out.println("main hehe");
    }
}
